package handler;

import enums.MessageType;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import protocol.Header;
import protocol.NettyMessage;

/**
 * 客户端发送心跳类
 * 握手成功之后,由客户端主动发送心跳信息,服务器端收到心跳消息之后,返回心跳应答消息,
 * 由于心跳消息的目的是为了检测链路的可用性,因此不需要携带消息体
 */
public class HeartBeatReqHandler extends ChannelInboundHandlerAdapter {
  //ScheduledFuture只是在Future基础上还集成了Comparable和Delayed的接口。使其具有延迟、排序、获得异步计算结果的特性。
  private volatile ScheduledFuture<?> heartBeat;

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    System.out.println("发送心跳:"+System.currentTimeMillis());
    NettyMessage message = (NettyMessage) msg;
    //握手成功,主动发送心跳消息
    if (message.getHeader() != null
          && message.getHeader().getType() == MessageType.LOGIN_RESP.value()){
      // 握手成功消息,启动无限循环定期发送心跳消息
        heartBeat = ctx.executor().scheduleAtFixedRate(
            new HeartBeatTask(ctx),0,500, TimeUnit.MILLISECONDS
        );
    }else if (message.getHeader() != null
      && message.getHeader().getType() == MessageType.HEARTBEAT_RESP.value()){
      System.out.println("client receive server heart beat  message : -->" + message);
    }else {
      ctx.fireChannelRead(msg);
    }
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    ctx.close();
    cause.printStackTrace();
  }

  private class HeartBeatTask implements Runnable{
    private final ChannelHandlerContext ctx;
    public HeartBeatTask(final ChannelHandlerContext ctx){
      this.ctx = ctx;
    }
    public void run() {
      NettyMessage heatBeat = buildHeatBeat();
      System.out.println("client send heart beat message tp server : --->" +heatBeat);
      ctx.writeAndFlush(heatBeat);
    }

    private NettyMessage buildHeatBeat(){
      NettyMessage message = new NettyMessage();
      Header header = new Header();
      header.setType(MessageType.LOGIN_REQ.value());
      message.setHeader(header);
      return message;
    }
  }

}
